<template>
  <div class="img_clipper" @dragstart.prevent @mousemove="handleMouseMove" @mouseup="handleMouseUp" @mouseleave="handleMouseout">
    <img ref="originImg" crossOrigin = 'anonymous' class="originImg" :src="imgSrc" alt="" @load="calc">
    <div class="mask">
      <div class="clipper" :style="{top: resize.top + 'px',right: resize.right + 'px', bottom: resize.bottom + 'px', left: resize.left + 'px'}">
        <div class="clipWrap">
          <img class="clipImg" :src="imgSrc" alt=""  :style="{width: width + 'px', top: -resize.top + 'px',right: -resize.right + 'px', bottom: -resize.bottom + 'px', left: -resize.left + 'px'}">
        </div>
        <div class="resize" @mousedown="handleMouseDown($event, 'mid')">
          <div class="point point-nw" @mousedown="handleMouseDown($event, 'nw')"></div>
          <div class="point point-ne" @mousedown="handleMouseDown($event, 'ne')"></div>
          <div class="point point-se" @mousedown="handleMouseDown($event, 'se')"></div>
          <div class="point point-sw" @mousedown="handleMouseDown($event, 'sw')"></div>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
  export default {
    props: {
      imgSrc: {
        type: String,
        default: null
      },
      ratio: {
        type: Number,
        default: null
      },
      resultType: {
        type: String,
        default: 'file'
      }
    },
    data () {
      return {
        width: null,
        height: null,
        resize: {
          top: 0,
          right: 0,
          bottom: 0,
          left: 0
        }
      }
    },
    watch: {
      ratio () {
        this.calc()
      }
    },
    methods: {
      // 计算宽高
      calc () {
        this.width = this.$el.offsetWidth
        this.height = this.$el.offsetHeight
        this.naturalWidth = this.$refs.originImg.naturalWidth // 获取图片的原始大小
        this.naturalHeight = this.$refs.originImg.naturalHeight
        if (this.ratio) {
          let h = this.width / this.ratio
          if (h < this.height) {
            this.resize.bottom = this.height - h
          } else {
            let w = this.height * this.ratio
            this.resize.right = this.width - w
          }
        }
      },
      // resize选区的相关方法
      handleMouseDown (e, type) {
        this.direction = type
        this.pageX = e.pageX
        this.pageY = e.pageY
        e.stopPropagation()
      },
      handleMouseUp () {
        this.direction = null
      },
      handleMouseMove (e) {
        let cWidth = 0
        let cHeight = 0
        if (this.direction === 'mid') {
          let top = this.resize.top + e.pageY - this.pageY
          let bottom = this.resize.bottom + this.pageY - e.pageY
          let left = this.resize.left + e.pageX - this.pageX
          let right = this.resize.right + this.pageX - e.pageX
          if (top > 0 && bottom > 0) {
            this.resize.top = top
            this.resize.bottom = bottom
          }
          if (right > 0 && left > 0) {
            this.resize.right = right
            this.resize.left = left
          }
        } else if (this.direction === 'nw') {
          let top = this.resize.top + e.pageY - this.pageY
          let left = this.resize.left + e.pageX - this.pageX
          if (this.ratio) {
            cWidth = this.width - left - this.resize.right
            cHeight = Math.floor(1 / this.ratio * cWidth)
            top = this.height - cHeight - this.resize.bottom
            if (top >= 0 && left >= 0) {
              this.resize.top = top
              this.resize.left = left
            }
          } else {
            top >= 0 && (this.resize.top = top)
            left >= 0 && (this.resize.left = left)
          }
        } else if (this.direction === 'ne') {
          let top = this.resize.top + e.pageY - this.pageY
          let right = this.resize.right + this.pageX - e.pageX
          if (this.ratio) {
            cWidth = this.width - this.resize.left - right
            cHeight = Math.floor(1 / this.ratio * cWidth)
            top = this.height - cHeight - this.resize.bottom
            if (top >= 0 && right >= 0) {
              this.resize.top = top
              this.resize.right = right
            }
          } else {
            top >= 0 && (this.resize.top = top)
            right >= 0 && (this.resize.right = right)
          }
        } else if (this.direction === 'se') {
          let bottom = this.resize.bottom + this.pageY - e.pageY
          let right = this.resize.right + this.pageX - e.pageX
          if (this.ratio) {
            cWidth = this.width - this.resize.left - right
            cHeight = 1 / this.ratio * cWidth
            bottom = this.height - cHeight - this.resize.top
            if (bottom >= 0 && right >= 0) {
              this.resize.bottom = bottom
              this.resize.right = right
            }
          } else {
            bottom >= 0 && (this.resize.bottom = bottom)
            right >= 0 && (this.resize.right = right)
          }
        } else if (this.direction === 'sw') {
          let bottom = this.resize.bottom + this.pageY - e.pageY
          let left = this.resize.left + e.pageX - this.pageX
          if (this.ratio) {
            cWidth = this.width - left - this.resize.right
            cHeight = 1 / this.ratio * cWidth
            bottom = this.height - cHeight - this.resize.top
            if (bottom >= 0 && left >= 0) {
              this.resize.bottom = bottom
              this.resize.left = left
            }
          } else {
            bottom >= 0 && (this.resize.bottom = bottom)
            left >= 0 && (this.resize.left = left)
          }
        }
        this.pageY = e.pageY
        this.pageX = e.pageX
      },
      handleMouseout () {
        this.direction = null
      },
      dataUrlToBlob (dataurl) {
        let arr = dataurl.split(',')
        let mime = arr[0].match(/:(.*?);/)[1]
        let bstr = atob(arr[1])
        let n = bstr.length
        let u8arr = new Uint8Array(n)
        while (n--) {
          u8arr[n] = bstr.charCodeAt(n)
        }
        return new Blob([u8arr], {type: mime})
      },
      // 剪切
      clip () {
        const clipW = this.width - this.resize.left - this.resize.right
        const clipH = this.height - this.resize.top - this.resize.bottom
        const scale = this.naturalWidth / this.width
        const canvas = document.createElement('canvas')
        canvas.width = scale * clipW
        canvas.height = scale * clipH
        const ctx = canvas.getContext('2d')
        const img = this.$refs.originImg
        ctx.drawImage(img, -this.resize.left * scale, -this.resize.top * scale, this.width * scale, this.height * scale)
        const dataUrl = canvas.toDataURL('image/jpeg')
        if (this.resultType === 'dataUrl') {
          return dataUrl
        } else if (this.resultType === 'file') {
          return this.dataUrlToBlob(dataUrl)
        }
      }
    }
  }
</script>
<style lang="scss">
  .img_clipper{
    &{position:relative;width:330px}
    .originImg{width:100%;}
    .mask{position:absolute;left:0;top:0;right:0;bottom:0;background:rgba(255,255,255,.5)}
    .clipper{position:absolute;left:0;top:0;right:0;bottom:0;border:1px dashed #ccc;}
    .clipImg{position:absolute;left:0;top:0;user-select: none;}
    .clipWrap{position:relative;width:100%;height:100%;overflow:hidden;}
    .resize{
      &{position:absolute;top:0;right:0;bottom:0;left:0;cursor:move;}
      .point{position:absolute;width:6px;height:6px;background:rgba(0,0,0,.6)}
      .point-nw{top:-3px;left:-3px;cursor:nw-resize;}
      .point-ne{top:-3px;right:-3px;cursor:ne-resize;}
      .point-se{bottom:-3px;right:-3px;cursor:se-resize;}
      .point-sw{bottom:-3px;left:-3px;cursor:sw-resize;}
    }
  }
</style>
